<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="Olj58" id="Olj58"><span data-lake-id="u7f6b916a" id="u7f6b916a">典型回答</span></h1>
  <p data-lake-id="u2d0f785e" id="u2d0f785e"><br></p>
  <p data-lake-id="u02bc5106" id="u02bc5106"><br></p>
  <p data-lake-id="u2bcca2e9" id="u2bcca2e9"><span data-lake-id="u7e9ebae8" id="u7e9ebae8">在使用SETNX实现的分布式锁中，因为存在锁无法续期导致并发冲突的问题，所以在真实的生产环境中用的并不是很多，其实，真正在使用Redis时，用的比较多的是基于Redisson实现分布式锁。</span></p>
  <p data-lake-id="u8caeed2a" id="u8caeed2a"><span data-lake-id="uafb49a64" id="uafb49a64">​</span><br></p>
  <blockquote data-lake-id="u92181321" id="u92181321">
   <p data-lake-id="u421dfe29" id="u421dfe29"><span data-lake-id="u2e0f10f7" id="u2e0f10f7">Redisson是一个基于Redis的Java客户端，它提供了丰富的功能，包括分布式锁的支持。 </span><a href="https://redisson.org/" target="_blank" data-lake-id="u663c9aac" id="u663c9aac"><span data-lake-id="ua826abf6" id="ua826abf6">https://redisson.org/</span></a></p>
   <p data-lake-id="ubf08a94a" id="ubf08a94a"><span data-lake-id="u70280e14" id="u70280e14">关于Redisson实现分布式锁可以查看：</span><a href="https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers" target="_blank" data-lake-id="uacdda6bb" id="uacdda6bb"><span data-lake-id="uec5fe8e5" id="uec5fe8e5">https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers</span></a></p>
  </blockquote>
  <p data-lake-id="u30226a02" id="u30226a02"><span data-lake-id="u8fba7fc7" id="u8fba7fc7">​</span><br></p>
  <p data-lake-id="u31997b3d" id="u31997b3d"><span data-lake-id="u663402d2" id="u663402d2">为了避免锁超时，Redisson中引入了看门狗的机制，他可以帮助我们在Redisson实例被关闭前，不断的延长锁的有效期。</span></p>
  <p data-lake-id="u35547dce" id="u35547dce"><span data-lake-id="u5ed40cb4" id="u5ed40cb4">​</span><br></p>
  <blockquote data-lake-id="u2dcee846" id="u2dcee846">
   <p data-lake-id="ubd91d0dd" id="ubd91d0dd"><span data-lake-id="u7275250a" id="u7275250a">默认情况下，看门狗的检查锁的超时时间是30秒钟，也可以通过修改</span><span data-lake-id="u0eb80567" id="u0eb80567">Config.lockWatchdogTimeout</span><span data-lake-id="ua9576893" id="ua9576893">来另行指定。</span></p>
  </blockquote>
  <p data-lake-id="u658b24a0" id="u658b24a0"><br></p>
  <h3 data-lake-id="XfI4y" id="XfI4y"><span data-lake-id="u444d02e9" id="u444d02e9">可重入锁</span></h3>
  <p data-lake-id="ue36838b9" id="ue36838b9"><br></p>
  <p data-lake-id="uaef69008" id="uaef69008"><span data-lake-id="ub0f4483c" id="ub0f4483c">基于Redisson可以非常简单的就获取一个可重入的分布式锁。基本步骤如下：</span></p>
  <p data-lake-id="u7e0fccce" id="u7e0fccce"><span data-lake-id="ub7e7aa8e" id="ub7e7aa8e">​</span><br></p>
  <p data-lake-id="u701e8e3a" id="u701e8e3a"><span data-lake-id="u871af090" id="u871af090">引入依赖：</span></p>
  <pre lang="java"><code>
&lt;dependency&gt;
    &lt;groupId&gt;org.redisson&lt;/groupId&gt;
    &lt;artifactId&gt;redisson&lt;/artifactId&gt;
    &lt;version&gt;最新版&lt;/version&gt; 
&lt;/dependency&gt;
</code></pre>
  <p data-lake-id="u70a67a78" id="u70a67a78"><span data-lake-id="u61423e55" id="u61423e55">​</span><br></p>
  <p data-lake-id="u1658ee9e" id="u1658ee9e"><span data-lake-id="u6fe2a5a1" id="u6fe2a5a1">定义一个Redisson客户端：</span></p>
  <pre lang="java"><code>
 /**
 * @author Hollis
 */
@Configuration
public class RedissonConfig {
    
    @Bean(destroyMethod="shutdown")
    public RedissonClient redisson() throws IOException {
        Config config = new Config();
		config.useSingleServer().setAddress("redis://127.0.0.1:6379");
		RedissonClient redisson = Redisson.create(config);
        return redisson;
    }
}

</code></pre>
  <p data-lake-id="u4eb78185" id="u4eb78185"><span data-lake-id="ud9616f77" id="ud9616f77">​</span><br></p>
  <p data-lake-id="ueede5d66" id="ueede5d66"><span data-lake-id="ud4c8418e" id="ud4c8418e">接下来，在想要使用分布式锁的地方做如下调用即可：</span></p>
  <p data-lake-id="ua3e55539" id="ua3e55539"><span data-lake-id="u7f136a08" id="u7f136a08">​</span><br></p>
  <pre lang="java"><code>
@Service
public class LockTestService{
    @Autowired
    RedissonClient redisson;
    
    public void testLock(){
        RLock lock = redisson.getLock("myLock");
        try {
            lock.lock();
            // 执行需要加锁的代码
        } finally {
            lock.unlock();
        }
    }
}

</code></pre>
  <p data-lake-id="u77336711" id="u77336711"><br></p>
  <p data-lake-id="u4c2725e3" id="u4c2725e3"><span data-lake-id="u66ba3482" id="u66ba3482">当然，也可以设置超时时间：</span></p>
  <p data-lake-id="uc9cb3ee6" id="uc9cb3ee6"><span data-lake-id="uee462c73" id="uee462c73">​</span><br></p>
  <pre lang="java"><code>
// 设置锁的超时时间为30秒
lock.lock(30, TimeUnit.SECONDS);
try {
    // 执行需要保护的代码
} finally {
    lock.unlock();
}

</code></pre>
  <p data-lake-id="u3a3db7e0" id="u3a3db7e0"><br></p>
  <p data-lake-id="u08872513" id="u08872513"><span data-lake-id="u375166c4" id="u375166c4">以上方式，实现的是一个可重入的分布式锁，也就是说，获取到锁的线程可以再次尝试获取锁，并且这个锁也只能被这个线程解锁。</span></p>
  <p data-lake-id="uf8f12cd2" id="uf8f12cd2"><span data-lake-id="ud57e39e1" id="ud57e39e1">​</span><br></p>
  <p data-lake-id="u9c628eeb" id="u9c628eeb"><span data-lake-id="u2be21914" id="u2be21914">除了可重入锁以外，Redisson还支持公平锁（FairLock）以及</span><span data-lake-id="u1f2e09c7" id="u1f2e09c7" style="color: rgb(31, 35, 40)">联锁（MultiLock）的使用。</span></p>
  <p data-lake-id="u8881b29c" id="u8881b29c"><span data-lake-id="ueb737591" id="ueb737591" style="color: rgb(31, 35, 40)">​</span><br></p>
  <p data-lake-id="u5b7279f6" id="u5b7279f6"><span data-lake-id="u14b610d0" id="u14b610d0" style="color: rgb(31, 35, 40)">公平锁：</span></p>
  <pre lang="java"><code>
RLock fairLock = redisson.getFairLock("anyLock");
fairLock.lock();
</code></pre>
  <p data-lake-id="u725d279b" id="u725d279b"><br></p>
  <p data-lake-id="udd196738" id="udd196738"><br></p>
  <p data-lake-id="u823ce1f5" id="u823ce1f5"><span data-lake-id="ud7bbf242" id="ud7bbf242">联锁：</span></p>
  <pre lang="java"><code>
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");

RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 同时加锁：lock1 lock2 lock3
// 所有的锁都上锁成功才算成功。
lock.lock();
...
lock.unlock();
</code></pre>
  <p data-lake-id="ucf510938" id="ucf510938"><br></p>
  <h3 data-lake-id="TZuUn" id="TZuUn"><span data-lake-id="u9d4b5bd8" id="u9d4b5bd8">RedLock</span></h3>
  <p data-lake-id="u288ea23d" id="u288ea23d"><br></p>
  <p data-lake-id="u1d75145c" id="u1d75145c"><span data-lake-id="u544637f8" id="u544637f8">​</span><br></p>
  <p data-lake-id="u4cad6c46" id="u4cad6c46"><span data-lake-id="u2d19e982" id="u2d19e982">为了解决Redis单点问题，引入了红锁的算法，Redisson中支持红锁的使用。示例在上面的文档中已经有了，这里就不再重复介绍了。</span></p>
  <p data-lake-id="u3170a180" id="u3170a180"><span data-lake-id="u8f720714" id="u8f720714">​</span><br></p>
  <h3 data-lake-id="kboD8" id="kboD8"><span data-lake-id="u7b08a7e5" id="u7b08a7e5">读写锁</span></h3>
  <p data-lake-id="u8c8b6ce0" id="u8c8b6ce0"><br></p>
  <p data-lake-id="u43582c50" id="u43582c50"><span data-lake-id="u89c56642" id="u89c56642">Redisson中支持分布式可重入读写锁，这种锁允许同时有多个读锁和一个写锁对同一个资源进行加锁。</span></p>
  <p data-lake-id="u1094a34d" id="u1094a34d"><span data-lake-id="u6437537b" id="u6437537b">​</span><br></p>
  <pre lang="java"><code>
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常见的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();
</code></pre>
  <p data-lake-id="udde65b7b" id="udde65b7b"><br></p>
 </body>
</html>